import os
import random

from appium.webdriver.common.appiumby import AppiumBy
from appium.webdriver.webdriver import WebDriver
from selenium.common import NoSuchElementException, TimeoutException
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait

from wework_app_po.utils.error_handle import black_wrapper
from wework_app_po.utils.log_utils import logger
from wework_app_po.utils.utils import Utils


class BasePage:
    """
    传递 driver
    封装常用的底层方法
    """

    IMPLICITLY_WAIT = 10

    def __init__(self, driver: WebDriver = None):
        self.driver = driver

    @black_wrapper
    def find(self, by, value):
        '''
        查找元素，返回元素
        :param by: 定位方式
        :param value: 定位表达式
        :return: 查找到的元素对象
        '''

        return self.driver.find_element(by, value)

    @black_wrapper
    def finds(self, by, value):
        '''
        查找多个元素，返回元素对象的列表
        :param by: 定位方式
        :param value: 定位表达式
        :return: 查找到的元素对象列表
        '''

        return self.driver.find_elements(by, value)

    def find_and_click(self, by, value):
        '''
        查找元素并点击
        :param by: 定位方式
        :param value: 定位表达式
        '''
        self.driver.find_element(by, value).click()

    def find_and_sendkeys(self, text, by, value):
        '''
        查找元素并输入内容
        :param text: 要输入的文本内容
        :param by: 定位方式
        :param value: 定位表达式
        '''
        self.driver.find_element(by, value).send_keys(text)

    def find_and_change(self, by, value, newtext):
        ele = self.find(by, value)
        # 点击姓名输入框
        ele.click()
        # 清空姓名输入框中内容
        ele.clear()
        # 输入姓名
        ele.send_keys(newtext)

    def find_and_reclick(self, by, value):
        # 定位性别框
        ele = self.find(by, value)
        # 获取当前性别输入值
        # text = ele.text
        text = random.choice(['男', '女'])
        # 点击性别框
        ele.click()
        # 选择性别
        self.find_and_click(AppiumBy.XPATH, f"//*[@text='{text}']")

    def get_texts(self, by, value):
        result = self.finds(by, value)
        res = [r.text for r in result]
        return res

    def set_implicitly_wait(self, time=1):
        '''
        设置隐式等待
        :param time: 隐式等待时间，默认值为1
        '''
        self.driver.implicitly_wait(time)  # 修改隐式等待时间

    def swip(self):
        # 获取屏幕高和宽
        window_size = self.driver.get_window_size()
        # 获取宽度
        width = window_size['width']
        # 获取高度
        height = window_size['height']

        # 设置滑动前后坐标位置
        # 横向取屏幕中间的位置
        startx = width // 2
        # 滑动前后横向不需要变动
        endx = width // 2
        # 纵向屏幕下方起始位置
        starty = int(height * 0.8)
        # 纵向屏幕上方结束位置
        endy = int(height * 0.2)

        # 滑动时间 单位毫秒
        duration = 2000
        # 调用swipe方法 传入参数
        self.driver.swipe(startx, starty, endx, endy, duration)

    def swipe_find(self, text, max_nums=5):
        # 使用find_element方法滑动寻找元素
        # 滑动次数，初始值为0
        num = 0
        # 两次滑动间隔时间长 是因为隐式等待设置的时间
        # 缩短隐式等待时间
        self.set_implicitly_wait(1)
        # 设置循环进行屏幕滑动，寻找目标元素
        while True:
            # 如果滑动次数超过目标值，结束循环
            if num > max_nums:
                # 打印提示信息
                print(f'超过{max_nums}次啦')
                # 恢复隐式等待时间
                self.set_implicitly_wait(self.IMPLICITLY_WAIT)
                # 抛出异常 # break的话，下一步还是会报错，直接在这里处理好
                raise NoSuchElementException(f"找了{num}次，未找到")
            # 捕捉异常
            try:
                # 寻找目标元素
                add_member_ele = self.driver.find_element(AppiumBy.XPATH, f'//*[@text="{text}"]')
            # 如果发生NoSuchElementException异常
            except NoSuchElementException as e:
                # 调用滑动屏幕方法
                self.swip()
                # 滑动次数+1
                num += 1
                # 打印滑动次数
                print(f'滑动第{num}次')
            else:
                # 如果没有异常，即找到目标元素
                # 恢复隐式等待时间
                self.set_implicitly_wait(self.IMPLICITLY_WAIT)
                # 返回目标元素
                return add_member_ele

    def swipe_find_and_click(self, text, max_nums=5):
        self.swipe_find(text, max_nums).click()

    def find_and_get_text(self, by, value):
        return self.find(by, value).text

    def get_tips(self):
        '''
        获取toast文本
        :return: 获取到的文本
        '''
        toast_txt = self.driver.find_element(AppiumBy.XPATH, '//*[@class="android.widget.Toast"]').text
        return toast_txt

    def wait_for_text(self, text, time=10):
        # 显示等待包含指定文本的元素出现 返回T/F
        try:
            WebDriverWait(self.driver, time).until(
                expected_conditions.visibility_of_element_located((AppiumBy.XPATH, f"//*[@text='{text}']")),
                message=f"'{text}'未找到")
            return True
        except TimeoutException as e:  # 要捕获具体的异常 不能捕获所有的
            # logger.error(f'"{text}"未找到')
            print(e)
            return False

    def wait_for_click(self, by, value, time=10):
        # 显示等待指定元素可点击 若可点击返回该元素，否则返回False
        try:
            ele = WebDriverWait(self.driver, time).until(expected_conditions.element_to_be_clickable((by, value)),
                                                         message='按钮不可点击')
            return ele
        except TimeoutException as e:  # 要捕获具体的异常 不能捕获所有的
            logger.error('按钮不可点击')
            return False

    @black_wrapper
    def wait_for_click_and_click(self, by, value, time=10):
        # 显示等待指定元素可点击 若可点击返回该元素，否则返回False
        ele = WebDriverWait(self.driver, time, 0.1).until(expected_conditions.element_to_be_clickable((by, value)),
                                                     message='按钮不可点击')
        ele.click()


    def wait_for_element_visable(self, ele):
        '''
        显式等待某个元素可见
        :param ele: 要等待的元素
        :return:
        '''
        WebDriverWait(self.driver, 10).until(expected_conditions.visibility_of_element_located(ele))

    def screenshot(self, root_path):
        logger.info("完成截图操作")
        # 使用当前时间作为截图的文件名
        image_name = Utils.get_current_time()+'.png'
        # 拼接当前图片保存的路径
        image_dir_path = os.sep.join([root_path, "..", "image/"])
        # 如果图片保存路径不存在
        if not os.path.isdir(image_dir_path):
            # 创建这个路径
            os.mkdir(image_dir_path)
        # 拼接图片保存路径
        image_path = image_dir_path + image_name
        logger.info(f"截图路径为 {image_path}")
        # 截图
        self.driver.save_screenshot(image_path)
        return image_path

    def save_page_source(self, root_path):
        logger.info("保存页面源码")
        # 使用当前时间作为页面源码的文件名
        page_source_name = Utils.get_current_time()+'_page_source.xml'
        # 拼接当前图片保存的路径
        page_source_dir_path = os.sep.join([root_path, "..", "page_source/"])
        # 如果保存路径不存在
        if not os.path.isdir(page_source_dir_path):
            # 创建这个路径
            os.mkdir(page_source_dir_path)
        # 拼接图片保存路径
        page_source_path = page_source_dir_path + page_source_name
        logger.info(f"page source 的保存路径为 {page_source_path}")
        # 写 page source 文件
        with open(page_source_path, "w", encoding='utf-8') as f:
            f.write(self.driver.page_source)
        return page_source_path